2015-06-01滚动监听 触摸点获取 Tranform RecealApp

概要

  • UITableView 滚动行为的监听,触摸点的获取
  • CGAffineTransformMakeTranslation和CGAffineTransformTranslate
  • reveal app 的项目集成
  • inputAccessoryView 遇到的几个问题

UITableView 滚动行为的监听,触摸点的获取

项目中有个需求是当 tableView 滚动的时候,将 tableView 上面的视图隐藏,就类似于 HeadView 那种推上去的效果. 但是按照 UI 层级来说,不能使用 Header ,所以有了这样一个需求.

网络上找到的零散知识

1
2
3
4
5
6
7
8
9
10
11
12
/*获得哪一行滚动上去了*/

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{



NSIndexPath *path = [self.bottomView indexPathForRowAtPoint:CGPointMake(scrollView.contentOffset.x, scrollView.contentOffset.y)];

NSLog(@"这是第%ld行",path.row);


}
1
2
3
4
5
6
7
8
9
/*获得触摸点的位置*/
UITableView *tableView=(UITableView *)self.view;
NSSet *touches = [event allTouches]; //包含所有的uitouch 单点触控就只有一个uitouch

UITouch *touch= [touches anyObject]; //获取触摸点在uitableVIEW上的位置
CGPoint p=[touch locationInView:tableView];
NSIndexPath *path= [tableView indexPathForRowAtPoint:p];
Book *book=self.books[path.row];
NSLog(@"row--%@",book.name);

但是使用的时候,结果始终是 0 ,就是不能正确取到触摸点的位置.
所以还是利用下面的方法:

1
2
3
4
5
6
7
8
9
10
11
12
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{



NSIndexPath *path = [self.bottomView indexPathForRowAtPoint:CGPointMake(scrollView.contentOffset.x, scrollView.contentOffset.y)];

// NSLog(@"这是第%ld行",path.row);

NSLog(@"%f,%f",scrollView.contentOffset.x,scrollView.contentOffset.y);


}

CGAffineTransformMakeTranslation和CGAffineTransformTranslate

简单提一下两个的区别(其他的缩放,旋转一个意思):

  • Translate(动词) 的是累加的形式,以前一个状态的 Transform 作为参照
  • MakeTranslation(名词) 是以最开始的状态为参照

主要是两者的使用场景:

  • 如果你的参数是累加的,那么通常用 MakeXXX能够完成需求
  • 如果参数是固定的,那么通常 动词的形式是你要的结果

我的需求的最终实现代码

最终效果实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pragma mark -system deleage
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{



NSIndexPath *path = [self.bottomView indexPathForRowAtPoint:CGPointMake(scrollView.contentOffset.x, scrollView.contentOffset.y)];

self.topView.transform = CGAffineTransformMakeTranslation(0,-scrollView.contentOffset.y);
self.bottomView.backgroundColor = [UIColor clearColor];
self.topView.transform = CGAffineTransformMakeTranslation(0, -scrollView.contentOffset.y);

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.25];
if (-scrollView.contentOffset.y<0) {
self.bottomView.y = 0;
self.headerView.backgroundColor = [UIColor grayColor];
}else{
self.bottomView.y = (self.topView.y+self.topView.height);
self.headerView.backgroundColor = [UIColor redColor];

}
[UIView commitAnimations];


}

reveal app 的使用

之前研究逆向的时候,用过,但是时间久了,居然忘记怎么集成了.
查阅了网上的资料,找到了方法

一. 简单的做法

安装Reveal不算复杂,要把Reveal用到工程中则需要把framework或者dylib编入。

  1. 打开Xcode工程

  2. 打开Revel工具,选择Menu->Help->Show Reveal Library in Finder,这样就会打开RevealApp里面带的库

  3. 把Reveal.framework加入工程,在弹出框中选中Copy items into destination group’s folder (if needed).
  4. 在工程设置中,在Other Linker Flags项增加-ObjC -framework Reveal 如果你使用的还是Xcode4,那么还需要增加-frame CFNetwork -frame QuartzCore -framework CoreGraphics

二.相对复杂,但是对项目的侵入性比较小的做法

  1. 在当前用户目录新建一个文件.lldbinit,位于~/.lldbinit,LLDB每次启动的时候都会加载这个文件。

  2. 在.lldbinit中输入如下内容:

1
2
3
4
5
6
7
command alias reveal_load_sim expr (void*)dlopen("/Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/libReveal.dylib", 0x2);

command alias reveal_load_dev expr (void*)dlopen([(NSString*)[(NSBundle*)[NSBundle mainBundle] pathForResource:@"libReveal" ofType:@"dylib"] cStringUsingEncoding:0x4], 0x2);

command alias reveal_start expr (void)[(NSNotificationCenter*)[NSNotificationCenter defaultCenter] postNotificationName:@"IBARevealRequestStart" object:nil];

command alias reveal_stop expr (void)[(NSNotificationCenter*)[NSNotificationCenter defaultCenter] postNotificationName:@"IBARevealRequestStop" object:nil];

上述文件创建了4个命令:

1
reveal_load_sim,reveal_load_dev, reveal_start 和 reveal_stop
  • reveal_load_sim 这个只在iOS模拟器上有效。它从Reveal的应用程序bundle中找到并加载libReveal.dylib(请确保你把Reveal安装到了系统的Application文件夹,如果你换地方了,你修改上述的文件)。

  • reveal_load_dev 这个命令在iOS设备和模拟器上都有效。不过,它需要你在Build Phase中的的Copy Bundle Resources中加上libReveal.dylib,请确保没有放到Link Binary With Libraries这个地方。

  • reveal_start 这个命令发出一个通知启动Reveal Server。

  • reveal_stop 这个命令发出一个通知停止Reveal Server。

请注意:只有在iOS应用发出了UIApplicationDidFinishLaunchingNotification通知之后,比如应用的delegate已经处理过application::didFinishLaunchingWithOptions:之后才能调用上面的revealload*命令,然后再调用reveal_start

在设备起来之后,你就可以断下应用,在LLDB提示框中输入上述的命令了。

上述的过程还需要手动输入,下面介绍如何设置条件断点,使得Reveal在启动之后自动加载。

在你的应用的application:didFinishLaunchingWithOptions 中的代码出加一个断点,然后右键,选择编辑断点。

输入如下图一样的命令:

重新运行下应用,如果控制台输出了如下信息:

1
Reveal server started.

说明成功了

个人推荐用第一种方法,然后项目发布的时候,记得删除即可

InputAccessoryView 可能遇到的问题

辅助布局的样式

1
UIBarButtonItem * button1 =[[UIBarButtonItem  alloc]initWithBarButtonSystemItem:                                        UIBarButtonSystemItemFlexibleSpace target:self action:nil];

定义普通的按钮

1
UIBarButtonItem * doneButton = [[UIBarButtonItem alloc]initWithTitle:@"完成" style:UIBarButtonItemStyleDone  target:self action:@selector(resignKeyboard)];

添加按钮

1
2
NSArray * buttonsArray = [NSArray arrayWithObjects:button1,button2,doneButton,nil];    
[topView setItems:buttonsArray];

参考网址:
http://www.cocoachina.com/bbs/read.php?tid=293372
http://blog.csdn.net/yongyinmg/article/details/39293015
http://blog.csdn.net/sakulafly/article/details/17994173